package replay

import (
	"fmt"
	"regexp"
	"strings"
	"time"
)

type TimeParser struct {
	rg *regexp.Regexp
}

var timeTokens = []string{":yyyy", "yyyy",
	":yy", "yy",
	":MM", "MM",
	":HH", "HH",
	":hh", "hh",
	":dd", "dd",
	":mm", "mm",
	":ss", "ss",
	":doy",
	":weekday",
	":wn",
	":isown",
	":isowy",
	":HC",
	":hc",
	":m5",
	":m10",
	":m15",
	":m30",
	":s2",
	":s5",
	":s10",
	":s15",
	":ms",
}

func (p *TimeParser) Init() {
	p.rg = regexp.MustCompile(`(` + strings.Join(timeTokens, `|`) + `)`)
}

func parseTimeToken(match string, now time.Time) string {
	switch match {
	case ":yyyy", "yyyy":
		return now.Format("2006")
	case ":yy", "yy":
		return now.Format("06")
	case ":MM", "MM":
		return now.Format("01")
	case ":dd", "dd":
		return now.Format("02")
	case ":HH", ":hh", "HH", "hh":
		return now.Format("15")
	case ":mm", "mm":
		return now.Format("04")
	case "ss", ":ss":
		return now.Format("05")
	case ":ms", "ms":
		return fmt.Sprintf("%03d", now.Nanosecond()/1e6)
	case "doy", ":doy":
		return fmt.Sprintf("%03d", now.YearDay())
	case "weekday", ":weekday":
		return fmt.Sprintf("%d", now.Weekday())
	case ":wn", "wn":
		week := WeekNumFromJan1Sun(now)
		return fmt.Sprintf("%.2d", week)
	case ":isown":
		_, week := now.ISOWeek()
		return fmt.Sprintf("%.2d", week)
	case ":isowy":
		year, _ := now.ISOWeek()
		return fmt.Sprintf("%.4d", year)
	case ":HC", "HC":
		return toHourChrUpcase(now)
	case ":hc", "hc":
		return toHourChr(now)
	case ":m5", "m5":
		mi := now.Truncate(time.Minute * 5)
		return fmt.Sprintf("%.2d", mi.Minute())
	case ":m10", "m10":
		mi := now.Truncate(time.Minute * 10)
		return fmt.Sprintf("%.2d", mi.Minute())
	case ":m15", "m15":
		mi := now.Truncate(time.Minute * 15)
		return fmt.Sprintf("%.2d", mi.Minute())
	case ":m30", "m30":
		mi := now.Truncate(time.Minute * 30)
		return fmt.Sprintf("%.2d", mi.Minute())
	case ":s5", "s5":
		mi := now.Truncate(time.Second * 5)
		return fmt.Sprintf("%.2d", mi.Second())
	case ":s2", "s2":
		mi := now.Truncate(time.Second * 2)
		return fmt.Sprintf("%.2d", mi.Second())
	case ":s10", "s10":
		mi := now.Truncate(time.Second * 10)
		return fmt.Sprintf("%.2d", mi.Second())
	case ":s15", "s15":
		mi := now.Truncate(time.Second * 15)
		return fmt.Sprintf("%.2d", mi.Second())
	case ":s30", "s30":
		mi := now.Truncate(time.Second * 30)
		return fmt.Sprintf("%.2d", mi.Second())
	default:
		return match
	}
}

func (p *TimeParser) Parse(s string, now time.Time) string {
	return p.rg.ReplaceAllStringFunc(s, func(match string) string {
		return parseTimeToken(match, now)
	})
}

var (
	tm TimeParser
)

func init() {
	tm.Init()
}

func ParseTimeFormatReg(s string, t time.Time) string {
	return tm.Parse(s, t)
}

func ParseTimeFormat(s string, t time.Time) string {
	for _, token := range timeTokens {
		s = strings.ReplaceAll(s, token, parseTimeToken(token, t))
	}
	return s
}

// A:0时, F(A+6):6时, (A+23):23时,
func toHourChrUpcase(atime time.Time) string {
	h := atime.Hour()
	i := int(rune('A'))
	rval := string(rune(i + h))
	return rval
}

func toHourChr(atime time.Time) string {
	h := atime.Hour()
	i := int(rune('a'))
	rval := string(rune(i + h))
	return rval
}

// 2022-01-01 是星期六
func WeekNumFromJan1Sun(t time.Time) int {
	year := t.Year()
	loc := t.Location()
	jan1 := time.Date(year, 1, 1, 0, 0, 0, 0, loc)

	// 1 月 1 日往前推到周日（weekday=0）
	sundayJan1 := jan1.AddDate(0, 0, -int(jan1.Weekday()))

	// 相差天数
	days := int(t.Sub(sundayJan1).Hours() / 24)
	return days/7 + 1
}
